package com.manage.common.util;



import java.util.concurrent.*;

/**
 * 线程池
 * @author duaiyu
 * @version V1.0
 * @date 2022/5/15
 * 来源：自研
 */
public class ThreadPoolUtil {
    /**
     * 线程池的实现
     * 线程池不建议使用Executors,Executors可以创建一个固定池大小的线程池，它的任务队列是无界的。
     * 任务队列无界的坏处就是，通过他创建的，固定池大小设置成了100，200.这时候因为它的任务队列无界，
     * 他就会贪得无厌，只要来任务了，就往里面放。这时候的问题就是，任务太多了，已经超出了能够处理笑话的程度了，
     * 但是又不报错，这时候任务在里面久久得不到执行。这就是阿里不允许使用的原因。
     *
     * api实现的四个线程池不建议使用的原因，小编不做介绍，大家自行百度了解
     * 这里实现ThreadPoolExecutor是建议使用的
     */
    public Object threadPoolExecutor(Runnable tasks){
        /**
         * 参数信息：
         * int corePoolSize     核心线程大小
         * int maximumPoolSize  线程池最大容量大小
         * long keepAliveTime   线程空闲时，线程存活的时间
         * TimeUnit unit        时间单位
         * BlockingQueue<Runnable> workQueue  任务队列。一个阻塞队列
         *
         * 任务队列的三种方式：
         * 1 直接提交策略
         *    工作队列的默认选项是 SynchronousQueue，它将任务直接提交给线程而不保持它们。
         * 在此，如果不存在可用于立即运行任务的线程，则试图把任务加入队列将失败，因此会构造一个新的线程。
         * 此策略可以避免在处理可能具有内部依赖性的请求集时出现锁。直接提交通常要求无界 maximumPoolSizes
         * 以避免拒绝新提交的任务。当命令以超过队列所能处理的平均数连续到达时，此策略允许无界线程具有增长的可能性。
         *     SynchronousQueue是无界的，也就是说他存数任务的能力是没有限制的，但是由于该Queue本身的特性，
         * 在某次添加元素后必须等待其他线程取走后才能继续添加。
         *
         * 2 无界队列
         *     使用无界队列（例如，不具有预定义容量的 LinkedBlockingQueue）将导致在所有 corePoolSize
         * 线程都忙时新任务在队列中等待。这样，创建的线程就不会超过 corePoolSize。（因此，maximumPoolSize的值
         * 也就无效了。）当每个任务完全独立于其他任务，即任务执行互不影响时，适合于使用无界队列；例如，
         * 在 Web页服务器中。这种排队可用于处理瞬态突发请求，当命令以超过队列所能处理的平均数连续到达时，
         * 此策略允许无界线程具有增长的可能性。
         *     LinkedBlockingQueue是大小不固定的BlockingQueue，若其构造时指定大小，生成的BlockingQueue有
         * 大小限制，不指定大小，其大小有Integer.MAX_VALUE来决定。其所含的对象是FIFO顺序排序的。
         *     PriorityBlockingQueue类似于LinkedBlockingQueue，但是其所含对象的排序不是FIFO，
         * 而是依据对象的自然顺序或者构造函数的Comparator决定。
         *
         * 3 有界队列
         *     当使用有限的 maximumPoolSizes时，有界队列（如 ArrayBlockingQueue）有助于防止资源耗尽，
         * 但是可能较难调整和控制。队列大小和最大池大小可能需要相互折衷：使用大型队列和小型池可以最大限度地降低
         * CPU使用率、操作系统资源和上下文切换开销，但是可能导致人工降低吞吐量。如果任务频繁阻塞（例如，
         * 如果它们是 I/O边界），则系统可能为超过您许可的更多线程安排时间。使用小型队列通常要求较大的池大小，
         * CPU使用率较高，但是可能遇到不可接受的调度开销，这样也会降低吞吐量。
         *
         * 拒绝策略
         * 1 AbortPolicy 直接抛出异常
         * 2 DiscardPolicy 放弃当前任务，并且不会抛出任何异常
         * 3 DiscardOldestPolicy 会将队列中最早添加的元素移除，
         *  再尝试添加，如果失败则按该策略不断重试
         * 4 CallerRunsPolicy 由调用线程（提交任务的线程）处理该任务，
         * 如果调用线程是主线程，那么主线程会调用执行器中的execute方法来
         * 执行改任务
         */
        ThreadPoolExecutor thread = new ThreadPoolExecutor(10,20,
                3, TimeUnit.SECONDS, new LinkedBlockingQueue<>(1024),
                new ThreadPoolExecutor.AbortPolicy());

        Object result = "";
        try{
            // 执行任务
            Future future = thread.submit(tasks);
            // 查看执行情况，有异常会在此显示
             result = future.get();
        }catch (InterruptedException e){
            e.printStackTrace();
        }catch (ExecutionException e){
            e.printStackTrace();
        }finally {
            thread.shutdown();
        }
        return result;
    }

}
